#!/usr/bin/env python
# -*- coding: utf-8 -*-
#--------------------------------在299行处可更改用户信息--------------------------
try:
    import json
except ImportError:
    import simplejson as json
import time
import urllib
import urllib2
import logging
from HandleSentence import get_words_rate

def _obj_hook(pairs):
    '''
    convert json object to python object.
    '''
    o = JsonObject()
    for k, v in pairs.iteritems():
        o[str(k)] = v
    return o

class APIError(StandardError):
    '''
    raise APIError if got failed json message.
    '''
    def __init__(self, error_code, error, request):
        self.error_code = error_code
        self.error = error
        self.request = request
        StandardError.__init__(self, error)

    def __str__(self):
        return 'APIError: %s: %s, request: %s' % (self.error_code, self.error, self.request)

class JsonObject(dict):
    '''
    general json object that can bind any fields but also act as a dict.
    '''
    def __getattr__(self, attr):
        return self[attr]

    def __setattr__(self, attr, value):
        self[attr] = value

def _encode_params(**kw):
    '''
    Encode parameters.
    '''
    args = []
    for k, v in kw.iteritems():
        qv = v.encode('utf-8') if isinstance(v, unicode) else str(v)
        args.append('%s=%s' % (k, urllib.quote(qv)))
    return '&'.join(args)

def _encode_multipart(**kw):
    '''
    Build a multipart/form-data body with generated random boundary.
    '''
    boundary = '----------%s' % hex(int(time.time() * 1000))
    data = []
    for k, v in kw.iteritems():
        data.append('--%s' % boundary)
        if hasattr(v, 'read'):
            # file-like object:
            ext = ''
            filename = getattr(v, 'name', '')
            n = filename.rfind('.')
            if n != (-1):
                ext = filename[n:].lower()
            content = v.read()
            data.append('Content-Disposition: form-data  name="%s"  filename="hidden"' % k)
            data.append('Content-Length: %d' % len(content))
            data.append('Content-Type: %s\r\n' % _guess_content_type(ext))
            data.append(content)
        else:
            data.append('Content-Disposition: form-data  name="%s"\r\n' % k)
            data.append(v.encode('utf-8') if isinstance(v, unicode) else v)
    data.append('--%s--\r\n' % boundary)
    return '\r\n'.join(data), boundary

_CONTENT_TYPES = { '.png': 'image/png', '.gif': 'image/gif', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.jpe': 'image/jpeg' }

def _guess_content_type(ext):
    return _CONTENT_TYPES.get(ext, 'application/octet-stream')

_HTTP_GET = 0
_HTTP_POST = 1
_HTTP_UPLOAD = 2

def _http_get(url, authorization=None, **kw):
    logging.info('GET %s' % url)
    return _http_call(url, _HTTP_GET, authorization, **kw)

def _http_post(url, authorization=None, **kw):
    logging.info('POST %s' % url)
    return _http_call(url, _HTTP_POST, authorization, **kw)

def _http_upload(url, authorization=None, **kw):
    logging.info('MULTIPART POST %s' % url)
    return _http_call(url, _HTTP_UPLOAD, authorization, **kw)

def _http_call(url, method, authorization, **kw):
    '''
    send an http request and expect to return a json object if no error.
    '''
    params = None
    boundary = None
    if method==_HTTP_UPLOAD:
        params, boundary = _encode_multipart(**kw)
    else:
        params = _encode_params(**kw)
    http_url = '%s?%s' % (url, params) if method==_HTTP_GET else url
    http_body = None if method==_HTTP_GET else params
    req = urllib2.Request(http_url, data=http_body)
    if authorization:
        req.add_header('Authorization', 'OAuth2 %s' % authorization)
    if boundary:
        req.add_header('Content-Type', 'multipart/form-data  boundary=%s' % boundary)
    resp = ''
    fails = 0
    while True:
        try:
            if fails > 2:
                break
            resp = urllib2.urlopen(req, timeout=90)
        except urllib2.URLError, e: 
            fails += 1
            logging.error('Error:%s when url:%s fails:%s' % (e, http_url, fails))
            time.sleep(9)
        else:
            break
    body = resp.read()
    r = json.loads(body, object_hook=_obj_hook)
    if hasattr(r, 'error_code'):
        raise APIError(r.error_code, getattr(r, 'error', ''), getattr(r, 'request', ''))
    return r

class HttpObject(object):

    def __init__(self, client, method):
        self.client = client
        self.method = method

    def __getattr__(self, attr):
        def wrap(**kw):
            if self.client.is_expires():
                raise APIError('21327', 'expired_token', attr)
            return _http_call('%s%s.json' % (self.client.api_url, attr.replace('__', '/')), self.method, self.client.access_token, **kw)
        return wrap

class APIClient(object):
    '''
    API client using synchronized invocation.
    '''
    def __init__(self, app_key, app_secret, redirect_uri=None, response_type='code', domain='api.weibo.com', version='2'):
        self.client_id = app_key
        self.client_secret = app_secret
        self.redirect_uri = redirect_uri
        self.response_type = response_type
        self.auth_url = 'https://%s/oauth2/' % domain
        self.api_url = 'https://%s/%s/' % (domain, version)
        self.access_token = None
        self.expires = 0.0
        self.get = HttpObject(self, _HTTP_GET)
        self.post = HttpObject(self, _HTTP_POST)
        self.upload = HttpObject(self, _HTTP_UPLOAD)

    def set_access_token(self, access_token, expires_in):
        self.access_token = str(access_token)
        self.expires = float(expires_in)

    def get_authorize_url(self, redirect_uri=None, display='default'):
        '''
        return the authroize url that should be redirect.
        '''
        redirect = redirect_uri if redirect_uri else self.redirect_uri
        if not redirect:
            raise APIError('21305', 'Parameter absent: redirect_uri', 'OAuth2 request')
        return '%s%s?%s' % (self.auth_url, 'authorize', \
                _encode_params(client_id = self.client_id, \
                        response_type = 'code', \
                        display = display, \
                        redirect_uri = redirect))

    def request_access_token(self, code, redirect_uri=None, uname='', upassword=''):
        '''
        return access token as object: {"access_token":"your-access-token","expires_in":12345678}, expires_in is standard unix-epoch-time
        '''
        redirect = redirect_uri if redirect_uri else self.redirect_uri
        g_type = 'authorization_code'
        if not redirect:
            g_type = 'password'
        r = _http_post('%s%s' % (self.auth_url, 'access_token'), \
                client_id = self.client_id, \
                client_secret = self.client_secret, \
                username = uname, password = upassword, \
                code = code, grant_type = g_type)
        r.expires_in += int(time.time())
        return r

    def is_expires(self):
        return not self.access_token or time.time() > self.expires

    def __getattr__(self, attr):
        return getattr(self.get, attr)
#获取前天的某条微博的ID
def get_timeline_id(statuses):
    yday = datetime.datetime.now().day -2
    for x in statuses:
        date = x.created_at.split(" ")
        for y in date:
            try:
                if (int(y) == yday):
                    return x.idstr
            except:
                pass
#获取最近的100条微博最早那一条的ID
def get_Htimeline_id(client):
    statuses = client.get.statuses__home_timeline(count=100).statuses
    timeline_id = statuses[99].idstr
    return timeline_id
#获取好友ID评分
def get_Uidtable(client):
    Clist=[]
    Rlist=[] 
    Flist=[]
    temp=set()
    idtable={}
    comments=client.get.comments__by_me().comments
    recomments=client.get.comments__to_me().comments
    favorites=client.get.favorites().favorites     
    for x in comments:
        Clist.append(str(x.status.user.id))#用户评论的微博博主ID
    for x in recomments:
        Rlist.append(str(x.user.id))#评论用户的博主ID
    for x in favorites:
        Flist.append(str(x.status.user.id))#用户收藏的微博的博主ID
    #print Clist
    for x in Clist:
        temp.add(x)
    for x in Rlist:
        temp.add(x)
    for x in Flist:
        temp.add(x)
    for x in temp:
        idtable[x]=(Clist.count(x)*2+Rlist.count(x)*3+Flist.count(x)*10)#给和用户有交互的博主评分
    return idtable
#获取微博评分
def groups_statuses_info(idstr,client,Uidtable,time_id):
    Gstatus=client.get.friendships__groups__timeline(list_id=idstr,since_id=time_id).statuses
    idlist=[]
    info={}
    for x in Gstatus:
        try:
            idlist.append(x.retweeted_status.idstr)
        except:
            idlist.append(x.idstr)
        try:
            info[x.idstr]=Uidtable[str(x.user.id)]
        except:
            info[x.idstr]=0
    for x in idlist:
        if (idlist.count(x)>1):
            info[x]=idlist.count(x)*200
    return info
#获取词频
def get_groups_words_rate(idstr,client,time_id):
    Lsentence = ''
    wordtable = {}
    Gstatus=client.get.friendships__groups__timeline(list_id=idstr,since_id=time_id).statuses
    for x in Gstatus:
        try:
            Lsentence = Lsentence + x.retweeted_status.text
        except:
            Lsentence = Lsentence + x.text
    Lsentence = Lsentence.encode('utf-8')
    wordtable = get_words_rate(Lsentence)
    return wordtable
#将所有微博词频内容存入一个总的字典中 key=词 value=词频
def get_words_set(wtables):
    Alltable = {}
    for x in wtables:
        if (x != []):
            for y in x.keys():
                Alltable[y] = Alltable.get(y,0) + x.get(y,0)
    return Alltable
    
if __name__ == '__main__':
    #main()
    try:
        start = time.clock()

        #step 1 定义 app key，app secret， user name, user password：

        APP_KEY = "1262673699"
        APP_SECRET = "6185cf040b403dfa35de9678b5e35baf"

        USER_NAME = "18610491651"  #授权用户名
        USER_PASSWD = "zsdc12"  #授权用户密码

        #step 2 获取OAuth2.0 Access Token:
        client = APIClient(app_key=APP_KEY, app_secret=APP_SECRET)
        r = client.request_access_token(0, None, USER_NAME, USER_PASSWD)
        client.set_access_token(r.access_token, r.expires_in)
        print r.access_token

        #step 3 使用获得的OAuth2.0 Access Token调用API
        print "本时段剩余访问次数：", client.get.account__rate_limit_status().remaining_ip_hits
        start_time = time.mktime(time.strptime("2013-8-1 00:00:00",'%Y-%m-%d %H:%M:%S'))
        end_time = time.mktime(time.strptime("2013-8-10 00:00:00",'%Y-%m-%d %H:%M:%S'))
        stop = time.clock()
        #好友ID评分
        Uidtable=get_Uidtable(client)
        print Uidtable
        Gtable={}#定义好友分组字典
        groups=client.get.friendships__groups().lists
        since_id = get_Htimeline_id(client)#获取最近的100条微博中最早一条的ID作为时限
        Wtables=[]
        for x in groups:
            Gtable[x.name] = x.idstr
            print '分组名' + x.name.encode('utf-8')+':'
            #获取好友分组内微博词频
            try:
                print 1
                Wtables.append(get_groups_words_rate(x.idstr,client,since_id))
            except:
                print 2
                Wtables.append({})
            
            #获取各个好友分组中的微博打分信息
            Stable = groups_statuses_info(x.idstr,client,Uidtable,since_id)
            status_id_sort = sorted(Stable.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)#对这些微博依据评分进行降序排序
            if(x.member_count>0):
                print "分组中推送前3条微博为：\n"
                try:
                    for i in range(0,2):
                        status = client.get.statuses__show(id=status_id_sort[i][0])
                        print status.text
                        print "by"
                        print status.user.name
                        time.sleep(0.1)
                except:
                    print "组内微博数量太少~不足三条哦"
            else:
                print "分组中没有成员"
        #获取分组内热词    
        Atable = get_words_set(Wtables)
        j = 0
        for x in groups:
            print '分组名' + x.name.encode('utf-8')+':'
            try:
                for y in Wtables[j].keys():
                    Wtables[j][y] = Wtables[j].get(y,0)/(Atable.get(y,0) - Wtables[j].get(y,0)+1)#用类似TF-DIF算法的方法来判断出热词
                words_sort = sorted(Wtables[j].items(), lambda x, y: cmp(x[1], y[1]), reverse=True)
                for m in range(0,9):
                    print words_sort[m][0]
                j = j + 1
            except:
                j = j + 1
                print '分组内信息不足'              
        print("总计用时：" + str(stop-start) + "秒")

    except Exception as pyOauth2Error:
        print pyOauth2Error
